package com.stars.easyms.rest.client.autoconfigure;

import com.stars.easyms.base.util.FastJsonUtil;
import com.stars.easyms.rest.client.properties.EasyMsRestClientProperties;
import com.stars.easyms.rest.client.template.EasyMsRestTemplate;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>className: EasyMsRestClientAutoConfiguration</p>
 * <p>description: EasyMsRestClient自动配置类</p>
 *
 * @author guoguifang
 * @version 1.7.3
 * @date 2021/3/3 8:02 下午
 */
@Configuration
@EnableConfigurationProperties(EasyMsRestClientProperties.class)
public class EasyMsRestClientAutoConfiguration {

    private EasyMsRestClientProperties easyMsRestClientProperties;

    public EasyMsRestClientAutoConfiguration(EasyMsRestClientProperties easyMsRestClientProperties) {
        this.easyMsRestClientProperties = easyMsRestClientProperties;
    }

    @Bean
    @ConditionalOnMissingBean(RestTemplate.class)
    public EasyMsRestTemplate easyMsRestTemplate() {
        EasyMsRestTemplate easyMsRestTemplate = new EasyMsRestTemplate(clientHttpRequestFactory());
        easyMsRestTemplate.setErrorHandler(new DefaultResponseErrorHandler());
        List<HttpMessageConverter<?>> localMessageConverters = new ArrayList<>();
        localMessageConverters.add(FastJsonUtil.getFastJsonHttpMessageConverter());
        for (HttpMessageConverter<?> messageConverter : easyMsRestTemplate.getMessageConverters()) {
            if (messageConverter instanceof StringHttpMessageConverter) {
                StringHttpMessageConverter stringHttpMessageConverter = (StringHttpMessageConverter) messageConverter;
                stringHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
            }
            localMessageConverters.add(messageConverter);
        }
        easyMsRestTemplate.setMessageConverters(localMessageConverters);
        return easyMsRestTemplate;
    }

    private ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
        registryBuilder.register("http", new PlainConnectionSocketFactory());

        // 判断是否检查https，如果不检查则重写https的校验
        if (easyMsRestClientProperties.isHttpsCheck()) {
            SSLConnectionSocketFactory sslConnectionSocketFactory = null;
            try {
                SSLContext sslContext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
                sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }}, new SecureRandom());
                sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            } catch (Exception e) {
                // ignore
            }
            if (sslConnectionSocketFactory != null) {
                httpClientBuilder.setSSLSocketFactory(sslConnectionSocketFactory);
                registryBuilder.register("https", sslConnectionSocketFactory);
            }
        }

        // 创建连接池
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registryBuilder.build());
        // 整个连接池的并发
        poolingHttpClientConnectionManager.setMaxTotal(easyMsRestClientProperties.getPool().getMaxTotal());
        // 每个主机的并发
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(easyMsRestClientProperties.getPool().getMaxPerRoute());
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
        // 重启策略
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
        // 设置超时时间，毫秒
        clientHttpRequestFactory.setConnectTimeout(easyMsRestClientProperties.getConnectTimeout());
        clientHttpRequestFactory.setReadTimeout(easyMsRestClientProperties.getReadTimeout());
        clientHttpRequestFactory.setConnectionRequestTimeout(easyMsRestClientProperties.getConnectionRequestTimeout());
        return clientHttpRequestFactory;
    }

}
